/**************************************************************************
 * 文件名  ：iic_hardware.c
 * 描述    ：硬件IIC程序  
****************************************************************************/
#include "iic_hardware.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"

#ifdef USE_HARDWARE_IIC  // 使用软件IIC（注：软件IIC和硬件IIC只能同时使用一种）

uint8_t dma_rx_buffer[2];
uint8_t dma_receive_flag = 0;

/* IIC发送多个数据 */
uint8_t iic_write_bytes(uint8_t addr, uint8_t *buf, uint8_t buf_size)
{ 
    uint32_t timeout;

    /*!< While the bus is busy */
    timeout = IIC_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(IIC_PORT, I2C_FLAG_BUSY))
    {
        if((timeout--) == 0) 
            return 0;
    }
    
    /*!< Send START condition */
    I2C_GenerateSTART(IIC_PORT, ENABLE);
    /*!< Check EV5 and clear it */
    timeout = IIC_LONG_TIMEOUT;
    while(!I2C_CheckEvent(IIC_PORT, I2C_EVENT_MASTER_MODE_SELECT))
    {
        if((timeout--) == 0) 
            return 0;
    }
    
    /*!< Send address for write */
    I2C_Send7bitAddress(IIC_PORT, (addr<<1), I2C_Direction_Transmitter);
    /*!< Check EV6 and clear it */
    timeout = IIC_LONG_TIMEOUT;
    while(!I2C_CheckEvent(IIC_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
    {
        if((timeout--) == 0) 
            return 0;
    }
    
    /*!< Send N byte data */
    while(buf_size--)
    {
        I2C_SendData(IIC_PORT, *buf);

        /*!< Check EV8 and clear it */
        timeout = IIC_LONG_TIMEOUT; 
        while(!I2C_CheckEvent(IIC_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
        {
            if((timeout--) == 0) 
                return 0;
        } 
    }

    /*!< Send STOP condition */
    I2C_GenerateSTOP(I2C1, ENABLE);

    /* If all operations OK, return 1 */
    return 1;
}

/**
  * @brief  This function handles DMA1 Channel 7 interrupt request.
  * @param  None
  * @retval None
  */
void DMA1_Channel7_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC7))
    {
        DMA_ClearITPendingBit(DMA1_IT_GL7);
        I2C_AcknowledgeConfig(IIC_PORT, DISABLE);
        I2C_GenerateSTOP(IIC_PORT, ENABLE);
        dma_receive_flag = 1;  // 已收到数据
    }
}

/* IIC接收多个数据 */
uint8_t iic_receive_bytes(uint8_t addr, uint8_t *buf, uint8_t buf_size)
{
    uint32_t timeout;

    /*!< While the bus is busy */
    timeout = IIC_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(IIC_PORT, I2C_FLAG_BUSY))
    {
        if((timeout--) == 0) 
            return 0;
    }

    /*!< Send START condition */
    I2C_GenerateSTART(IIC_PORT, ENABLE);
    /*!< Check EV5 and clear it */
    timeout = IIC_LONG_TIMEOUT;
    while(!I2C_CheckEvent(IIC_PORT, I2C_EVENT_MASTER_MODE_SELECT))
    {
        if((timeout--) == 0) 
            return 0;
    }
    
    /*!< Send address for read */
    I2C_Send7bitAddress(IIC_PORT, (addr<<1), I2C_Direction_Receiver);
    /*!< Test on EV6 and clear it */
    timeout = IIC_LONG_TIMEOUT;
    while(!I2C_CheckEvent(IIC_PORT, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {
        if((timeout--) == 0) 
            return 0;
    }  
    
    I2C_AcknowledgeConfig(IIC_PORT, ENABLE);
    
    /* Inform the DMA that the next End Of Transfer Signal will be the last one */
    I2C_DMALastTransferCmd(IIC_PORT, ENABLE); 

    /* Configure the DMA Rx Channel with the buffer address and the buffer size */
    DMA_Cmd(I2C_DMA_CHANNEL_RX, DISABLE); 
    DMA_SetCurrDataCounter(DMA1_Channel7, buf_size);
    DMA_Cmd(I2C_DMA_CHANNEL_RX, ENABLE); 

    /* 接收数据 */
    timeout = IIC_LONG_TIMEOUT;
    while(!dma_receive_flag)
    {// 等待数据接收完成
        if((timeout--) == 0) 
        {
            dma_receive_flag = 0;
            return 0;
        }
    }
    memcpy(buf, dma_rx_buffer, buf_size);

    /* If all operations OK, return 1 */
    return 1;
}

/* IIC初始化 */
void iic_init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;  
    DMA_InitTypeDef   DMA_InitStructure;   
    I2C_InitTypeDef  I2C_InitStructure; 

    /*!< I2C_SCL_GPIO_CLK and I2C_SDA_GPIO_CLK Periph clock enable */
    RCC_APB2PeriphClockCmd(IIC_SCL_CLOCK | IIC_SDA_CLOCK, ENABLE);

    /*!< I2C Periph clock enable */
    RCC_APB1PeriphClockCmd(IIC_PORT_CLOCK, ENABLE);
        
    /*!< GPIO configuration */  
    /*!< Configure I2C pins: SCL */
    GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);

    /*!< Configure I2C pins: SDA */
    GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure); 

    /* Configure and enable I2C DMA RX Channel interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = I2C_DMA_RX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2C_DMA_PREPRIO;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = I2C_DMA_SUBPRIO;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);  
    
    /*!< I2C DMA RX channels configuration */
    /* Enable the DMA clock */
    RCC_AHBPeriphClockCmd(I2C_DMA_CLK, ENABLE);

    /* I2C RX DMA Channel configuration */
    DMA_DeInit(I2C_DMA_CHANNEL_RX);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C_DR_Address;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&dma_rx_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
    DMA_InitStructure.DMA_BufferSize = 2;         
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(I2C_DMA_CHANNEL_RX, &DMA_InitStructure);  
    
    /* Enable the DMA Channels Interrupts */
    DMA_ITConfig(I2C_DMA_CHANNEL_RX, DMA_IT_TC, ENABLE);  

    /*!< I2C configuration */
    /* I2C configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
    
    /* Apply I2C configuration after enabling it */
    I2C_Init(IIC_PORT, &I2C_InitStructure);

    /* I2C Peripheral Enable */
    I2C_Cmd(IIC_PORT, ENABLE);

    /* Enable the I2C peripheral DMA requests */
    I2C_DMACmd(IIC_PORT, ENABLE);
}
#endif
